<template>
	<view>
		<!--内容插槽-->
		<template v-if="list.length>0">
			<slot :list="list"></slot>
		</template>

		<!--骨架屏插槽-->
		<template v-if="list.length === 0 && status === 'loading'">
			<slot name="skeleton"></slot>
		</template>

		<!--为空展示-->
		<template v-if="list.length === 0 && status === 'noMore'">
			<view class="empty">
				<image :src="emptyImg" class="img" mode="widthFix" />
			</view>
			<slot name="emptyTip">
				<view class="empty_tip">{{emptyText}}</view>
			</slot>

		</template>

		<uni-load-more :status="status" :showIcon="showIcon" @clickLoadMore="handleErr" :contentText="contentText"
			iconSize="15" :showText="showText" />
	</view>
</template>

<script setup>
	import { ref, onMounted, reactive, watch } from 'vue';
	import { onReachBottom } from '@dcloudio/uni-app';
	import request from '@/utils/common/request/index';

	const props = defineProps({
		reqUrl: {
			type: String,
			required: true,
		},
		method: {
			type: String,
			default: 'GET',
		},
		limit: {
			type: [String, Number],
			default: 10,
		},
		reqData: {
			type: Object,
			default: function() {
				return {};
			},
		},
		finishedText: {
			type: String,
			default: '没有更多数据了',
		},
		emptyText: {
			type: String,
			default: '暂无信息',
		},
		formatData: {
			type: Boolean,
			default: false,
		},
		handleFormat: {
			type: Function,
			default: function(data) {
				return data;
			},
		},
		immediatecheck: {
			type: Boolean,
			default: true
		},
		emptyImg: {
			type: String,
			default: '/static/image/empty.png'
		}
	});

	onMounted(() => {
		if (props.immediatecheck === false) return; //自定义请求时机时初始化时不请求
		onLoad();
	});
	onReachBottom(() => {
		if (status.value === 'loading') return;
		onLoad();
	});
	/*组件变量*/
	const contentText = reactive({
		//加载提示
		contentdown: '加载失败，点击重试',
		contentrefresh: '加载中...',
		contentnomore: props.finishedText,
	});
	let status = ref('loading');
	let page = 0; //当前页
	let lastLoadFail = false; //上一次加载更多请求是否失败
	let showIcon = ref(true); //是否显示loading图标 加载出错提示时不展示
	let showText = ref(true);
	let list = ref([]);

	watch(() => list.value,
		(data) => {
			contentText.contentnomore = data.length === 0 ? ' ' : props.finishedText
		}, { deep: true })

	const onLoad = function() {
		//加载更多处理函数(初始化加载也会触发)
		if (status.value === 'noMore') return;
		if (!showIcon.value) showIcon.value = true;
		if (!showText.value) showText.value = true;
		status.value = 'loading';
		page = lastLoadFail ? page : page + 1;
		req(false);
	};

	const handleErr = function() {
		status.value === 'more' && onLoad();
	};

	/**暴露方法供父组件使用 */
	const resetRequest = function(clear = true) {
		//外部筛选条件改变时，提供此方法触发重新加载
		if (clear) list.value = [];
		page = 1;
		status.value = 'loading';
		if (!showIcon.value) showIcon.value = true;
		if (!showText.value) showText.value = true;
		return req(true);
	};
	const captureList = function() {
		return list.value;
	};
	/*提供给scroll-view手动调用加载下一页*/
	const loadMore = function() {
		if (status.value === 'loading') return;
		onLoad();
	}

	defineExpose({ resetRequest, captureList, loadMore });

	/**
	 * 请求列表函数
	 * @param isRefresh true为下拉刷新阶段
	 */
	const req = function(isRefresh) {
		return new Promise((resolve) => {
			let reqTimeId = setTimeout(() => {
				request({
						url: props.reqUrl,
						method: props.method,
						data: {
							page,
							limit: props.limit,
							...props.reqData,
						},
					})
				.then(res => {
					/**判断分页请求是否最后一页 */
					if (res.current_page === res.last_page || res.current_page == undefined)
						status.value =
						'noMore';
					if (props.formatData) {
						if (res.current_page === undefined) {
							res = props.handleFormat(res);
						} else {
							res.data = props.handleFormat(res);
						}
					}
					// * 为了兼容不支持分页的接口
					let data = res.current_page !== undefined ? res.data : res;

					list.value = isRefresh ? data : list.value.concat(data);

					lastLoadFail = false; //重置上一次加载更多加载失败为false
					if (status.value !== 'noMore') {
						status.value = '';
						showText.value = false;
					}
				})
				.catch(() => {
					showIcon.value = false; //提示加载出错，此时隐藏图标，点击时重新请求
					status.value = 'more';
					lastLoadFail = true; //设置上一次加载更多加载失败
				})
				.finally(() => {
					/**如果父页面需要获取是否加载完毕(比如下拉刷新时加载完毕关闭下拉刷新)，返回promise供使用 */
					resolve(true);
				});
				clearTimeout(reqTimeId);
			}, 150);
		});
	};
</script>

<style lang="scss" scoped>
	.empty {
		text-align: center;
		padding: 40px 0 20px;

		.img {
			width: 250px;
		}
	}

	.empty_tip {
		text-align: center;
		font-size: 13px;
		color: #999;
	}
</style>